package gui;

import javax.swing.*;
import javax.swing.tree.*;
import javax.swing.event.*;

import java.awt.*;
import java.awt.event.*;

import java.util.*;
import util.Line;
import db.*;

//import att.grappa.*;

//////////////////////////////////////////////////////////////////////////
//// CodeBrowser
/**

@author Ivan Jeukens
@version v 0.1 19/06/2002
*/
public class CodeBrowser extends JFrame {

    public CodeBrowser() {
        super();
        setSize(1000, 700);
        _currentActor = null;
    }

    public CodeBrowser(ClassInfo info) {
        super();

        setSize(1000, 700);
        setTitle("Actor " + info.getName());
        _currentActor = info;

        JPanel main = new JPanel();
        main.setLayout(new BorderLayout());

        JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);

        _buildCodePanels();
        JScrollPane sp = new JScrollPane(_codePanel);
        splitPane.setLeftComponent(sp);

        //_buildDrawPanel();
        //sp = new JScrollPane(_drawPanel);
        //splitPane.setRightComponent(sp);

        main.add(splitPane, BorderLayout.CENTER);

        _buildHierPanel();
        sp = new JScrollPane(_hierPanel);
        main.add(sp, BorderLayout.WEST);

        getContentPane().add(main);

        _buildMenu();
    }

    public static final Color BackgroundColor = new Color(0xe5e5e5);

    ///////////////////////////////////////////////////////////////////
    ////                         public methods                    ////

    public void addEdge(ClassData cinfo, Line l1, Line l2) {

    }

    public void setLineForeground(ClassData cinfo, Line l, Color color) {
        JTextArea ta = _getTextArea(cinfo, l);
        ta.setForeground(color);
    }

    public void setLineBackground(ClassData cinfo, Line l, Color color) {
        JTextArea ta = _getTextArea(cinfo, l);
        ta.setBackground(color);
    }

    ///////////////////////////////////////////////////////////////////
    ////                           private methods                 ////

    private void _buildCodePanels() {
        _codePanel = new JPanel();
        BoxLayout boxl = new BoxLayout(_codePanel, BoxLayout.Y_AXIS);
        _codePanel.setLayout(boxl);

        _classCode = new HashMap();

        // Constroi as textareas para cada classe deste ator
        ClassData cinfo = _currentActor.getRootClass();
        _displayingClass = cinfo;
        while(cinfo != null) {
            if(cinfo.getName().equals("ptolemy.kernel.util.NamedObj") ||
               cinfo.getName().equals("ptolemy.kernel.Entity") ||
               cinfo.getName().equals("ptolemy.kernel.ComponentEntity") ||
               cinfo.getName().equals("ptolemy.actor.AtomicActor") ||
               cinfo.getName().equals("ptolemy.actor.TypedAtomicActor")) break;

            LinkedList code = cinfo.getCode();

            HashMap textElements = new HashMap();
            for(int i = 0;i < code.size();i++) {
                Line l = (Line) code.get(i);
                JTextArea ta = new JTextArea();
                ta.setEditable(false);
                
                StringBuffer buf = new StringBuffer();
                for(int j = 0;j < l.getIdent();j++) {
                    buf.append(" ");
                }            
                buf.append(l.getText());                
                for(int j = 0;j < l.getSpaces() - 1;j++) {
                    buf.append("\n");
                }
                ta.setText(buf.toString());
                ta.setRows(1);
                textElements.put(l, ta);

                if(cinfo == _currentActor.getRootClass()) {
                    _codePanel.add(ta);
                }
            }
            _classCode.put(cinfo, textElements);
            cinfo = cinfo.getSuperClass();
        }
    }

    private void _buildHierPanel() {
        _hierPanel = new JPanel();
        _hierPanel.setBackground(BackgroundColor);
        ClassData cinfo = _currentActor.getRootClass();
        DefaultMutableTreeNode topNode = 
	        new DefaultMutableTreeNode(_currentActor);
        while(cinfo != null) {
            if(cinfo.getName().equals("ptolemy.kernel.util.NamedObj") ||
               cinfo.getName().equals("ptolemy.kernel.Entity") ||
               cinfo.getName().equals("ptolemy.kernel.ComponentEntity") ||
               cinfo.getName().equals("ptolemy.actor.AtomicActor") ||
               cinfo.getName().equals("ptolemy.actor.TypedAtomicActor")) break;
               
            DefaultMutableTreeNode node =
	        new DefaultMutableTreeNode(cinfo);
            topNode.add(node);
            cinfo = cinfo.getSuperClass();
        }

        _hierTree = new JTree(topNode);
        _hierTree.setBackground(BackgroundColor);
        
        HierTreeCellRenderer render = new HierTreeCellRenderer();
        render.setBackground(BackgroundColor);
        render.setBackgroundNonSelectionColor(BackgroundColor);
        _hierTree.setCellRenderer(render);

        _hierTree.getSelectionModel().setSelectionMode(
	    TreeSelectionModel.SINGLE_TREE_SELECTION);
	_hierTree.putClientProperty("JTree.lineStyle", "Angled");
	_hierTree.setEditable(false);        
        _hierTree.addTreeSelectionListener(new TreeSelectionListener() {
            
            public void valueChanged(TreeSelectionEvent e) {
                DefaultMutableTreeNode node = (DefaultMutableTreeNode)
                    _hierTree.getLastSelectedPathComponent();
                if(node != null) {
                    // 1. Determina a classe
                    dbInfo info = (dbInfo) node.getUserObject();
                    ClassData cinfo;
                    if(info instanceof ClassInfo) {
                        cinfo = (ClassData) _currentActor.getRootClass();
                    }
                    else {
                         cinfo = (ClassData) info;
                    }
                    if(cinfo == _displayingClass) return;
                    _displayingClass = cinfo;

                    // 2. Atualiza o panel do codigo, para o novo codigo
                    _codePanel.removeAll();
                    HashMap textelements = (HashMap) _classCode.get(cinfo);
                    // as linhas do codigo devem estar na ordem correta, logo
                    // tenho que seguir pelo code
                    LinkedList code = cinfo.getCode();
                    for(int i = 0;i < code.size();i++) {
                        Line l = (Line) code.get(i);
                        JTextArea ta = (JTextArea) textelements.get(l);
                        _codePanel.add(ta);
                    }
                    // 3. Atualiza o estado do drawpanel
                    // ....

                    pack();
                }
            }
        });
        
        _hierPanel.add(_hierTree);
    }

    /*private void _buildDrawPanel() {
        _drawPanel = new DrawPanel();
        _drawPanel.setBackground(BackgroundColor);
    }*/

    private JTextArea _getTextArea(ClassData cinfo, Line l) {
        HashMap textelements = (HashMap) _classCode.get(cinfo);
        return (JTextArea) textelements.get(l);
    }

    private void _buildMenu() {
        JMenuBar mb = new JMenuBar();
        setJMenuBar(mb);

        JMenu view = new JMenu("View");

	JMenuItem mi = new JMenuItem("API methods");
        mi.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if(_displayingClass == null) return;

                /*
                Iterator methods = _displayingClass.methodGraphsIterator();
                while(methods.hasNext()) {
                    MethodGraph mg = (MethodGraph) methods.next();
                    Iterator nodes = mg.nodesIterator();
                    while(nodes.hasNext()) {
                        MethodGraphNode mgnode = (MethodGraphNode) nodes.next();
                        if(mgnode.getType() == MethodGraphNode.AUXILIAR ||
                           mgnode.getType() == MethodGraphNode.LOOPHEAD) continue;                        
                        
                        MethodCallNode mcnode = mgnode.getMethodCallNode();
                        Line l = mcnode.getLine();
                        JTextArea ta = _getTextArea(_displayingClass, l);
                        ta.setForeground(Color.red);
                                                
                        for(int i = 0;i < mgnode.outputSize();i++) {
                            MethodGraphNode out =  mgnode.getOutputNode(i);
                            if(out.getType() == MethodGraphNode.AUXILIAR) continue;
                            
                            MethodCallNode mc = out.getMethodCallNode();
                            Line l2 = mc.getLine();
                            JTextArea ta2 = _getTextArea(_displayingClass, l2);
                            
                            EdgeLayoutElement el = new EdgeLayoutElement(10, 
                                ta.getY(), 50, 100, 180, 90);
                            _drawPanel.addLayoutElement(el);
                            
                        }
                    }
                } */
	    }
        });
        view.add(mi);

        mb.add(view);
    }
    
    /* Limpa os paineis do code e do grafo */
    private void _resetPanels() {
        if(_displayingClass != null) {
            HashMap textelements = (HashMap) _classCode.get(_displayingClass);
            Collection c = textelements.values();
            Iterator ite = c.iterator();
            while(ite.hasNext()) {
                JTextArea ta = (JTextArea) ite.next();
                ta.setForeground(Color.black);
            }
        }
        
        // _drawPanel.reset();
    }

    ///////////////////////////////////////////////////////////////////
    ////                         private variables               ////

    private ClassInfo _currentActor;
    private ClassData _displayingClass;
    
    private JPanel _codePanel;
    private JPanel _hierPanel;
    //private DrawPanel _drawPanel;

    private JTree _hierTree;

    private HashMap _classCode;

    ///////////////////////////////////////////////////////////////////
    ////                         Inner class                       ////

    public class HierTreeCellRenderer extends DefaultTreeCellRenderer {

        public Component getTreeCellRendererComponent(JTree tree,
                Object value, boolean selected, boolean expanded, boolean leaf,
                int row, boolean hasFocus) {

	    DefaultTreeCellRenderer component = (DefaultTreeCellRenderer)
	        super.getTreeCellRendererComponent(tree, value,
                        selected, expanded, leaf, row, hasFocus);

	    return component;
        }
    }
}
